/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package me.zhengjie.modules.enrstu.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.enrstu.domain.AdministrativeDivision;
import me.zhengjie.modules.enrstu.domain.Community;
import me.zhengjie.modules.enrstu.domain.SchoolDistrict;
import me.zhengjie.modules.enrstu.repository.AdministrativeDivisionRepository;
import me.zhengjie.modules.enrstu.repository.CommunityRepository;
import me.zhengjie.modules.enrstu.repository.SchoolDistrictRepository;
import me.zhengjie.modules.enrstu.service.AdministrativeDivisionService;
import me.zhengjie.modules.enrstu.service.SchoolService;
import me.zhengjie.modules.enrstu.service.dto.SchoolCreateOrUpdate;
import me.zhengjie.modules.enrstu.service.dto.SchoolDto;
import me.zhengjie.modules.enrstu.service.dto.SchoolQueryCriteria;
import me.zhengjie.modules.enrstu.domain.School;
import me.zhengjie.modules.enrstu.repository.SchoolRepository;
import me.zhengjie.modules.enrstu.service.mapstruct.SchoolMapper;
import me.zhengjie.modules.system.domain.Dept;
import me.zhengjie.modules.system.domain.User;
import me.zhengjie.modules.system.repository.DeptRepository;
import me.zhengjie.modules.system.repository.UserRepository;
import me.zhengjie.modules.system.service.DeptService;
import me.zhengjie.modules.system.service.dto.DeptDto;
import me.zhengjie.utils.*;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
* @website https://eladmin.vip
* @description 服务实现
* @author yyx
* @date 2024-10-14
**/
@Slf4j
@Service("schoolServiceImpl")
@RequiredArgsConstructor
@Setter
public class SchoolServiceImpl implements SchoolService{

    private final SchoolRepository schoolRepository;
    private final SchoolMapper schoolMapper;
    private final CommunityRepository cyRepository;
    private final AdministrativeDivisionRepository adRepository;
    private final AdministrativeDivisionService adService;
    private final UserRepository userRepository;
    private final DeptRepository deptRepository;
    private final DeptService deptService;
    private final SchoolDistrictRepository sdRepository;



    @Override
    public PageResult<SchoolDto> queryAll(SchoolQueryCriteria criteria, Pageable pageable){
        if (ObjectUtil.isNotNull(criteria.getSchoolName())) {
            if (criteria.getSchoolName().length() > 20) {
                throw new BadRequestException("学校名称不能超过20个字符");
            }
        }
        criteria.setDeptPid(userRepository.findById(SecurityUtils.getCurrentUserId()).orElseGet(User::new).getDept().getId());
        Page<School> page = schoolRepository.findAll((root, criteriaQuery, criteriaBuilder) -> {
            Predicate predicate =  QueryHelp.getPredicate(root,criteria,criteriaBuilder);
            criteriaQuery.orderBy(criteriaBuilder.desc(root.get("gmtModified")));
          return predicate;
        },pageable);
        return PageUtil.toPage(page.map(schoolMapper::toDto));
    }

    @Override
    public List<SchoolDto> queryAll(SchoolQueryCriteria criteria){
        criteria.setDeptPid(userRepository.findById(SecurityUtils.getCurrentUserId()).orElseGet(User::new).getDept().getId());
        return schoolMapper.toDto(schoolRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
    @Transactional
    public SchoolDto findById(String id) {
        School school = schoolRepository.findOne((Root<School> root, CriteriaQuery<?> query, CriteriaBuilder cb)->{
            Predicate schoolId = cb.equal(root.get("schoolId"), id);
            Predicate createId = cb.equal(root.get("deptPid"), userRepository.findById(SecurityUtils.getCurrentUserId()).orElseGet(User::new).getDept().getId());
            return cb.and(schoolId,createId);
        }).orElseGet(School::new);
        ValidationUtil.isNull(school.getSchoolId(),"School","schoolId",id);
        return schoolMapper.toDto(school);
    }

    @Transactional(rollbackFor = Exception.class)
    public void create(School resources) {
        //学校名称不超过20个字符
        if (ObjectUtil.isNotNull(resources.getSchoolName())){
            if (resources.getSchoolName().length() > 20){
                throw new BadRequestException("学校名称不能超过20个字符");
            }
        }

        //判断实体类是否每个必填项属性是否填写
        Map<String, Object> beanMap = BeanUtil.beanToMap(resources, false, false);
        beanMap.forEach((key, value)->{
            if (ObjectUtil.equal(key, "deptId") || ObjectUtil.equal(key, "createId") || ObjectUtil.equal(key, "districtId") || ObjectUtil.equal(key, "schoolStatus") || ObjectUtil.equal(key, "gmtCreate") || ObjectUtil.equal(key, "gmtModified") || ObjectUtil.equal(key, "schoolId")|| ObjectUtil.equal(key, "deptPid")){
                return;
            }
            if (ObjectUtil.isNull(value)){
                throw  new BadRequestException("存在必填项未填写，请补充完整后启用" + key);
            }
        });
        //校验：学校名称是否已存在
        if(schoolRepository.count((Root<School> root, CriteriaQuery<?> query, CriteriaBuilder cb)->{
            return cb.equal(root.get("schoolName"), resources.getSchoolName());
        }) > 0){
            throw new BadRequestException("学校名称已存在！");
        }
        resources.setSchoolId(IdUtil.simpleUUID());
        resources.setCreateId(SecurityUtils.getCurrentUserId());
        //启动状态默认为开启
        if (ObjectUtil.isNull(resources.getSchoolStatus())){
            resources.setSchoolStatus(1);
        }
        //每个配置的学校，都将自动生成为一个部门，方便后续报名管理的账号配置以及授权和审核
        Dept dept = new Dept();
        dept.setDeptSort(999);
        dept.setName(resources.getSchoolName());
        dept.setEnabled(resources.getSchoolStatus() == 1);
        dept.setPid(userRepository.findById(SecurityUtils.getCurrentUserId()).orElseGet(User::new).getDept().getId());
        deptService.create(dept);
        resources.setDeptId(dept.getId());
        resources.setDeptPid(dept.getPid());
        schoolRepository.save(resources);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(SchoolCreateOrUpdate resources) {
        if(ObjectUtil.isNull(resources.getSchoolId())){
            throw new BadRequestException("学校ID不能为空");
        }
        School school = schoolMapper.toEntity(this.findById(resources.getSchoolId()));
        //校验
        if(!ObjectUtil.equal(school.getSchoolName(),resources.getSchoolName())) {
            if(schoolRepository.count((Root<School> root, CriteriaQuery<?> query, CriteriaBuilder cb)->{
                Predicate id = cb.notEqual(root.get("schoolId"), school.getSchoolId());
                Predicate schoolName = cb.equal(root.get("schoolName"), resources.getSchoolName());
                return cb.and(id,schoolName);
            }) > 0){
                throw new BadRequestException("学校名称已存在！");
            }
        }
        if(!ObjectUtil.equal(school.getDistrictId(),resources.getDistrictId())){
            //判断是否更新为没有归属学区：如果上送学区id或者置为空字符串，如果是则将学区id更新为null
            if (ObjectUtil.isNull(resources.getDistrictId()) || ObjectUtil.equal(resources.getDistrictId(),"")){
                resources.setDistrictId(null);
            }
        }
        BeanUtils.copyProperties(resources,school);
        schoolRepository.save(school);
        Dept dept = deptRepository.findById(school.getDeptId()).orElseGet(Dept::new);
        dept.setName(resources.getSchoolName());
        dept.setEnabled(resources.getSchoolStatus() == 1);
        deptRepository.save(dept);

    }

    @Override
    @Transactional
    public void deleteAll(String id) {
        School school = schoolMapper.toEntity(this.findById(id));
        ValidationUtil.isNull( school.getSchoolId(),"School","id",id);
        if(ObjectUtil.notEqual(school.getCreateId(), SecurityUtils.getCurrentUserId())){
            throw new BadRequestException("非创建人不允许删除");
        }
        Set<DeptDto> depts = new HashSet<>();
        depts.add(deptService.findById(school.getDeptId()));
        deptService.verification(depts);
        deptService.delete(depts);
        schoolRepository.deleteById(id);
    }

    @Override
    public void download(List<SchoolDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (SchoolDto school : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("学校名称", school.getSchoolName());
            map.put("学校类型", school.getSchoolType());
            map.put("状态", school.getSchoolStatus() == 0 ? "禁用":"正常");
            map.put("归属学区", sdRepository.findById(school.getDistrictId()).orElseGet(SchoolDistrict::new).getSchoolDistrictName());
            map.put("归属教育局",deptRepository.findById(school.getSchoolEduId()).orElseGet(Dept::new).getName());
            map.put("联系状态", school.getSchoolLandline());
            map.put("更新时间戳", school.getGmtModified());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public List<Dept> queryEducationAll() {
        //获取创建人的部门id
        Long currentUserId = SecurityUtils.getCurrentUserId();
        User user = userRepository.findById(currentUserId).orElseGet(User::new);
        Dept dept = deptRepository.findById(user.getDept().getPid()).orElseGet(Dept::new);
        List<Dept> edu = deptRepository.findByPid(dept.getId());
        // 临时变量
        List<Dept> temp = new ArrayList<>(edu);
        while (!temp.isEmpty()) {
            List<Dept> newDepts = new ArrayList<>();
            for (Dept dep : temp) {
                // 获取子部门id
                List<Dept> dp = deptRepository.findByPid(dep.getId());
                edu.addAll(dp);
                newDepts.addAll(dp);
            }
            temp = newDepts;
        }
        return edu.stream().filter(dep->{return StrUtil.contains(dep.getName(), "教育");}).collect(Collectors.toList());
    }

    @Override
    public Long total(String id) {
        return schoolRepository.countByDistrictId(id);
    }

    @Override
    public List<SchoolDto> querySchoolList(String schoolDistrictId) {
        return schoolRepository.findAllByDistrictId(schoolDistrictId).stream().map(school ->{
            SchoolDto schoolDto = new SchoolDto();
            BeanUtils.copyProperties(school, schoolDto);
            return schoolDto;
        }).collect(Collectors.toList());
    }

    @Override
    public List<SchoolDto> findSchoolList(Long communityAdId, boolean isPolicyCare) {
        if (isPolicyCare){
            //获取当前用户返回当前用户所在社区行政信息
            AdministrativeDivision ad = adRepository.findByAdministrativeDivisionId(communityAdId);
            //获取该社区对应的省/市
            AdministrativeDivision pads = adRepository.findBySignAndLevel(ad.getAdministrativeDivisionSign(),10);
            String deptName = "";
            //判断是否为直辖市
            if (adService.isMunicipality(pads.getAdministrativeDivisionName())){
                deptName = this.getPadInfo(ad.getAdministrativeDivisionParentId(),30);
            }else {
                //获取市级名称
                deptName = this.getPadInfo(ad.getAdministrativeDivisionParentId(),20);
            }
            //通过行政区名称获取该市/区的部门信息：配置部门时按照行政区名称进行配置的
            Dept dept = deptRepository.findByNameLike(deptName);
            log.info("dept::{}",dept);
            if (ObjectUtil.isNull(dept)){
                throw new BadRequestException(pads.getAdministrativeDivisionName()+"该市/区暂不支持本系统的幼升小报名招生！");
            }

            Dept sclDept = deptRepository.findSclDept(deptRepository.findByNameLike(pads.getAdministrativeDivisionName()).getId());

            List<School> school = schoolRepository.findByDeptPid(sclDept.getId());
            if (school.isEmpty()){
                throw new BadRequestException("您所在的地区暂无幼升小招生计划！");
            }
            //政策照顾对象，返回所有学校
            return schoolMapper.toDto(schoolRepository.findByDeptPid(sclDept.getId()));
        }
        //非政策照顾对象,返回社区对应学区名下的所有学校
        Community community = cyRepository.findByAdId(communityAdId);
        if (community == null){
            throw new BadRequestException("暂无上送社区行政id相关信息！");
        }
        List<School> schools = schoolRepository.findAllByDistrictId(community.getDistrictId());

        if (schools.isEmpty()){
            throw new BadRequestException(community.getCommunityName()+",该社区暂无招生计划！");
        }
        return schoolMapper.toDto(schoolRepository.findAllByDistrictId(community.getDistrictId()));
    }



    @Override
    public void download(HttpServletResponse response) {

        try {
            Map<String,Object> map = new LinkedHashMap<>();
            List<Map<String, Object>> list = new ArrayList<>();
            map.put("学校名称", "");
            map.put("学校类型", "");
            map.put("状态", "");
            map.put("学校联系电话", "");
            map.put("学校直属教育局 ", "");
            map.put("所属学区 ", "");
            list.add(map);
            FileUtil.downloadExcel(list, response);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    private String getPadInfo(Long id, Integer level){
        String deptName;
        Long temp = id;
        //获取区级名称
        for (;;){
            //查询条件
            AdministrativeDivision pad = adRepository.findByAdministrativeDivisionId(temp);
            //结束条件
            if (pad.getAdministrativeDivisionId() == null){
                throw new BadRequestException("上送社区行政id错误！");
            }
            //中止条件
            if(Objects.equals(pad.getAdministrativeDivisionLevel(), level)){
                deptName = pad.getAdministrativeDivisionName();
                break;
            }
            //循环条件
            temp = pad.getAdministrativeDivisionParentId();
        }
        return deptName;
    }





}